package cn.k7g.alloy.ioc.processor;

import cn.k7g.alloy.core.objectmapper.AlloyAnnotationIntrospector;
import cn.k7g.alloy.core.objectmapper.BigIntegerSerializer;
import cn.k7g.alloy.core.objectmapper.EnumSerializer;
import cn.k7g.alloy.core.objectmapper.GlobalDateFormatter;
import cn.k7g.alloy.core.objectmapper.LongToString;
import cn.k7g.alloy.core.objectmapper.SortOrderDeserializer;
import cn.k7g.alloy.core.objectmapper.SortOrderSerializer;
import cn.k7g.alloy.core.objectmapper.Timestamp;
import cn.k7g.alloy.core.objectmapper.TimestampSerializer;
import cn.k7g.alloy.ioc.AlloyConfig;
import cn.k7g.alloy.model.SortOrder;
import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

/**
 * 增强ObjectMapper
 * @author victor-wu
 * @date 2021/9/27 下午1:10
 */
public class EnhanceObjectMapperProcess implements BeanPostProcessor {
    boolean enhanceObjectMapper;
    private BeanFactory beanFactory;

    public EnhanceObjectMapperProcess(boolean enhanceObjectMapper, BeanFactory beanFactory) {
        this.enhanceObjectMapper = enhanceObjectMapper;
        this.beanFactory = beanFactory;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ObjectMapper && enhanceObjectMapper) {
            enhanceObjectMapper0((ObjectMapper) bean);
        }
        return bean;
    }

    private void enhanceObjectMapper0(ObjectMapper objectMapper) {
        // 序列化注解
        AnnotationIntrospector annotationIntrospector = objectMapper.getSerializationConfig().getAnnotationIntrospector();

        AlloyAnnotationIntrospector alloyAnnotationIntrospector = beanFactory.getBean(AlloyAnnotationIntrospector.class);
        AnnotationIntrospector pair = AnnotationIntrospector.pair(annotationIntrospector, alloyAnnotationIntrospector);
        objectMapper.setAnnotationIntrospector(pair);


        AlloyConfig config = beanFactory.getBean(AlloyConfig.class);

        // 支持ENUM序列化
        SimpleModule module = new SimpleModule();
        module.addSerializer(Enum.class, new EnumSerializer());
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(config.getLocalDateTimePattern())));
        module.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(config.getLocalDatePattern())));
        module.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(config.getLocalTimePattern())));
        // TimeExtra 的特殊处理类型
        module.addSerializer(Timestamp.class, new TimestampSerializer());
        module.addSerializer(SortOrder.class, new SortOrderSerializer());
        module.addSerializer(BigInteger.class, new BigIntegerSerializer());
        module.addSerializer(Long.class, new LongToString());

        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(config.getLocalDateTimePattern())));
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(config.getLocalDatePattern())));
        module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(config.getLocalTimePattern())));
        module.addDeserializer(SortOrder.class, new SortOrderDeserializer());

        objectMapper.registerModule(module);
        objectMapper.setDateFormat(new GlobalDateFormatter());
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    }
}
